# -*- coding: utf-8 -*-

"""
Created on Fri Jun  8 18:43:24 2018

@main purpose: to define some class that act as a convienient interface to the module matplotlib.



@author: Administrator

"""

#%%

import matplotlib as mpl
#这一行代码是指保存图片，不在console里面显示。
mpl.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
import matplotlib.patches as mpatches
from sklearn.linear_model import LinearRegression
import numpy as np
from .basic import Basic_const

#%%
#the logic of the code below is that Figure_single and Figure_multi are used to detemined how many subplots(axe) one figure object should have,
#and then Axe_bar,Axe_scatter,Axe_histogram were used to plot each axe of the figure defined by Figure_single or Figure_multi.
class Figure_singleaxe(Basic_const):
  @classmethod
  def singleaxe(cls,figsize_tuple,style):
    #如果给定了style且在plt.style.available内，则设置，
    #如果没有给定或者不在plt.style.available内，则跳过
    if style in plt.style.available:
      plt.style.use(style)
    #此函数主要是在类的外部被调用，根据传入的figsize_tuple生成Figure object, 然后根据axe_numb,column_numb，生成对应布局的的多个axe
    #然后将生成的fig和axe_array返回
    fig = plt.figure(figsize=figsize_tuple)

    #sharex=True, sharey=True还暂不确定是什么意思
    axe = fig.add_subplot(111)
    return fig,axe


class Figure_multiaxe(Basic_const):
  @classmethod
  def multiaxe(cls,figsize_tuple,axe_numb,column_numb,style):
    #如果给定了style且在plt.style.available内，则设置，
    #如果没有给定或者不在plt.style.available内，则跳过
    if style in plt.style.available:
      plt.style.use(style)
    #此函数主要是在类的外部被调用，根据传入的figsize_tuple生成Figure object, 然后根据axe_numb,column_numb，生成对应布局的的多个axe
    #然后将生成的fig和axe_array返回
    fig = plt.figure(figsize=figsize_tuple)
    #如果axe_numb可以被self.column_numb整除，row_numb等于取整的商，如果不能，则等于取整的商+1
    row_numb = cls.special_division(axe_numb,column_numb)
    #sharex=True, sharey=True还暂不确定是什么意思,之所以加reshape(),是为了将二维array拉成一维的，便于后边使用for循环
    #便于for循环。
    axe_array = fig.subplots(row_numb,column_numb, sharex=True, sharey=True).reshape(row_numb*column_numb,cls.one_numb)
    return fig,axe_array
  
  @staticmethod
  def special_division(denominator,numerator ):
    #此函数主要是在类的内部被multi_axe调用
    quotient = denominator // numerator
    residue = denominator % numerator
    return quotient if residue==0 else quotient+1


class Figure_gridspec(Basic_const):
  @classmethod
  def gridspec(cls,figsize_tuple,style):
    #如果给定了style且在plt.style.available内，则设置，
    #如果没有给定或者不在plt.style.available内，则跳过
    if style in plt.style.available:
      plt.style.use(style)
    #此函数主要是在类的外部被调用，根据传入的figsize_tuple生成Figure object, 然后根据axe_numb,column_numb，生成对应布局的的多个axe
    #然后将生成的fig和axe_array返回
    fig = plt.figure(figsize=figsize_tuple,linewidth=0,constrained_layout=True)
    fig.subplots_adjust(wspace =0.4, hspace =0.8)
    gs = fig.add_gridspec(3, 2)
    axe_list = []
    axe_list.append(fig.add_subplot(gs[0, :]))
    axe_list.append(fig.add_subplot(gs[1, 0]))
    axe_list.append(fig.add_subplot(gs[1, -1]))
    axe_list.append(fig.add_subplot(gs[2, :]))

    
    return fig,axe_list
  
#%%
#the main useness of this class is to plot bar and inherited by Error_barplot, Error_barplot_across_region, 
#Coeff_barplot_across_subject_regionwise   
    
class Axe_bar(Basic_const):
  @staticmethod  
  def axe(axe,x_data, y_data, error_data, x_label, y_label, title,bar_color,barwidth,error_color,xticklabel_list,major_locator):
    print('axe:,',axe)
    print('x_data:',x_data)
    print('y_data:',y_data)
    print('error_data:',error_data)
    print('xticklabel_list:',xticklabel_list)
    #设置axe本身
    axe.set_facecolor('w')
    
    #设置axis
    axe.spines['bottom'].set_color('black')
    axe.spines['left'].set_color('black')
    axe.yaxis.set_major_locator(MultipleLocator(major_locator))
    
    #设置ticks
    axe.set_xticks(x_data)
    axe.set_xticklabels(labels=xticklabel_list)
    axe.tick_params(length=0)
    
    #显示核心信息
    # Draw bars, position them in the center of the tick mark on the x-axis
    axe.bar(x_data, y_data, width=barwidth, color = bar_color, align = 'center')

    if len(error_data) != 0:
      print('len(error_data):',len(error_data))
      # Draw error bars to show standard deviation, set ls to 'none'
      # to remove line between points
      axe.errorbar(x_data, y_data, yerr = error_data, color = error_color, ls = 'none', lw = 2, capthick = 1)
    
    #其他辅助信息
    axe.grid(b=True,axis='y',color='lightgray', linestyle='--' )
    axe.set_ylabel(y_label)
    axe.set_xlabel(x_label)
    axe.set_title(title)
    
    return axe

class Axe_scatter(Basic_const):
  @staticmethod
  def axe(axe,x_data, y_data, x_label, y_label, title):
    print('axe:,',axe)

    x_data = np.array(x_data).reshape(-1,1)
    y_data = np.array(y_data).reshape(-1,1)
    lr_model = LinearRegression().fit(x_data,y_data)
    predict = lr_model.predict(x_data)
    print('x_data:',x_data)
    print('y_data:',y_data)
    print('predict:',predict)
    #设置axe本身
    axe.set_facecolor('w')
    
    #设置axis
    axe.set_xlim(-0.6,0.8)
    axe.set_ylim(-1.5,0.8)
    axe.spines['bottom'].set_color('black')
    axe.spines['left'].set_color('black')
    axe.xaxis.set_major_locator(MultipleLocator(0.3))
    axe.yaxis.set_major_locator(MultipleLocator(0.6))
    #设置ticks  set_major_locator
    axe.tick_params(length=1)
    
    #显示核心信息
    axe.scatter(x_data, y_data,s=15, c='black' )
    axe.plot(x_data,predict,color='#E9CFAE',linewidth=0.8)
    
    #其他辅助信息
    axe.grid(b=True,axis='both',which='major',color='lightgray', linestyle='--' )
    axe.set_ylabel(y_label)
    axe.set_xlabel(x_label)
    axe.set_title(title)
    
    return axe

class Axe_histogram(Basic_const):
  @staticmethod
  def axe(axe,x_data, y_data, error_data, x_label, y_label, title,bar_color,barwidth,error_color,xticklabel_list):
    pass


class Axe_legend(Basic_const):
  @staticmethod
  def axe(axe,color_list,label_list):
    print('#############################in axe_legend')
    if not len(color_list) == len(label_list):
      raise Exception('color_list and label_list must have same amount of elements')
      print('color_list:',color_list)
      print('label_list:',label_list)
    
    axe.set_facecolor('w')
    patch_list = [mpatches.Patch(color=color,label=label) for color,label in zip(color_list,label_list) ]
    axe.legend(handles=patch_list,loc=10,facecolor='w',edgecolor='w')
    axe.grid(b=False)
    axe.tick_params(length=0)
    return axe

#%%
